//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//*********************************************************

namespace Microsoft.Research.ScientificWorkflow.ManagementStudioModels
{
    using System;
    using System.ComponentModel;
    using System.Windows;
    using System.Windows.Media.Imaging;
    using System.Collections.ObjectModel;
    using System.Collections.Generic;
    using System.Linq;

    /// <summary>
    /// The abstract model that is implemented by the models of the registry manager.
    /// </summary>
    public abstract class BaseRegMgrModel : INotifyPropertyChanged
    {
        #region Private fields
                
        private string name;

        private string label;

        private string description;

        private Guid id;

        private string createdBy;

        private DateTime createdDate;

        private DateTime lastModifiedTime;

        private string lastModifiedBy;

        private ObservableCollection<BaseRegMgrModel> children = new ObservableCollection<BaseRegMgrModel>();
        
        private bool isSelected;

        private BaseRegMgrModel parent;

        private int version;

        #endregion

        /// <summary>
        /// Gets or sets the name.
        /// </summary>
        /// <value>The name.</value>
        public string Name
        {
            get
            {
                return this.name;
            }
            set
            {
                this.name = value;
                this.RaisePropertyChanged("Name");
            }
        }
        
        /// <summary>
        /// Gets or sets the label.
        /// </summary>
        /// <value>The label.</value>
        public virtual string Label
        {
            get
            {
                return this.label;
            }
            set
            {
                this.label = value;
                this.RaisePropertyChanged("Label");
            }
        }

        /// <summary>
        /// Gets or sets the description.
        /// </summary>
        /// <value>The description.</value>
        public string Description
        {
            get
            {
                return this.description;
            }
            set
            {
                this.description = value;
                this.RaisePropertyChanged("Description");
            }
        }

        /// <summary>
        /// Gets or sets the id.
        /// </summary>
        /// <value>The id.</value>
        public virtual Guid Id
        {
            get
            {
                return this.id;
            }
            set
            {
                this.id = value;
            }
        }

        /// <summary>
        /// Gets or sets the created by.
        /// </summary>
        /// <value>The created by.</value>
        public string CreatedBy
        {
            get { return createdBy; }
            set
            {
                createdBy = value;
                this.RaisePropertyChanged("CreatedBy");
            }
        }

        /// <summary>
        /// Gets or sets the created date.
        /// </summary>
        /// <value>The created date.</value>
        public virtual DateTime CreatedDate
        {
            get
            {
                return createdDate;
            }
            set
            {
                createdDate = value;
                this.RaisePropertyChanged("CreatedDate");
            }
        }

        /// <summary>
        /// Gets or sets the last modified time.
        /// </summary>
        /// <value>The last modified time.</value>
        public virtual DateTime LastModifiedTime
        {
            get
            {
                return this.lastModifiedTime;
            }
            set
            {
                this.lastModifiedTime = value;
                this.RaisePropertyChanged("LastModifiedTime");
            }
        }

        /// <summary>
        /// Gets or sets the last modified by.
        /// </summary>
        /// <value>The last modified by.</value>
        public string LastModifiedBy
        {
            get
            {
                return this.lastModifiedBy;
            }
            set
            {
                this.lastModifiedBy = value;
                this.RaisePropertyChanged("LastModifiedBy");
            }
        }
        
        /// <summary>
        /// Gets the children.
        /// </summary>
        /// <value>The children.</value>
        public ObservableCollection<BaseRegMgrModel> Children
        {
            get { return children; }
        }

        /// <summary>
        /// Gets or sets the saved image.
        /// </summary>
        /// <value>The saved image.</value>
        public virtual BitmapImage ItemIcon
        {
            get;
            set;
        }

        /// <summary>
        /// Gets a value indicating whether this instance is selected.
        /// </summary>
        /// <value>
        /// 	<c>true</c> if this instance is selected; otherwise, <c>false</c>.
        /// </value>
        public virtual bool IsSelected
        {
            get
            {
                return this.isSelected;
            }
            set
            {
                this.isSelected = value;
                this.RaisePropertyChanged("IsSelected");
            }
        }
        
        /// <summary>
        /// Gets or sets the parent.
        /// </summary>
        /// <value>The parent.</value>
        public virtual BaseRegMgrModel Parent
        {
            get
            {
                return parent;
            }
            set
            {
                parent = value;
                this.RaisePropertyChanged("Parent");
            }
        }

        /// <summary>
        /// Gets or sets a value indicating whether this instance is latest.
        /// </summary>
        /// <value><c>true</c> if this instance is latest; otherwise, <c>false</c>.</value>
        public bool IsLatest { get; set; }

        /// <summary>
        /// Gets or sets the version.
        /// </summary>
        /// <value>The version.</value>
        public int Version
        {
            get
            {
                return this.version;
            }
            set
            {
                this.version = value;
                this.RaisePropertyChanged("Version");
            }
        }

        #region INotifyPropertyChanged Members

        /// <summary>
        /// Occurs when property changed.
        /// </summary>
        public event PropertyChangedEventHandler PropertyChanged;

        /// <summary>
        /// Raises the property changed.
        /// </summary>
        /// <param name="name">The name.</param>
        protected void RaisePropertyChanged(string name)
        {
            if (PropertyChanged != null)
                PropertyChanged(this, new PropertyChangedEventArgs(name));
        }

        #endregion

        /// <summary>
        /// Gets the model by id.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <param name="coll">The collection.</param>
        /// <returns></returns>
        public virtual BaseRegMgrModel GetModelById(BaseRegMgrModel model, IEnumerable<BaseRegMgrModel> collection)
        {
            return BaseRegMgrModel.GetModelById(model.Id, collection, model.Parent);
        }

        /// <summary>
        /// Gets the model by id.
        /// </summary>
        /// <param name="id">The id.</param>
        /// <param name="coll">The collection.</param>
        /// <returns></returns>
        private static BaseRegMgrModel GetModelById(Guid id, IEnumerable<BaseRegMgrModel> collection, BaseRegMgrModel parentModel)
        {
            BaseRegMgrModel model = null;
            if (!id.Equals(Guid.Empty))
            {
                foreach (BaseRegMgrModel currentModel in collection)
                {
                    if (currentModel.Id.Equals(id))
                    {
                        if (parentModel != null && currentModel.Parent != null)
                        {
                            if (!currentModel.Parent.Id.Equals(parentModel.Id))
                            {
                                continue;
                            }
                        }

                        model = currentModel;
                        break;
                    }
                    else
                    {
                        model = BaseRegMgrModel.GetModelById(id, currentModel.Children, parentModel);
                        if (model != null)
                        {
                            break;
                        }
                    }
                }
            }

            return model;
        }

        /// <summary>
        /// Updates the specified model.
        /// </summary>
        /// <param name="model">The model.</param>
        public virtual void Update(BaseRegMgrModel model)
        {
            if (model != null)
            {
                this.Name = model.Name;
                this.Label = model.Label;
                this.Description = model.Description;
                this.CreatedDate = model.CreatedDate;
                this.CreatedBy = model.CreatedBy;
                this.LastModifiedTime = model.LastModifiedTime;
                this.LastModifiedBy = model.LastModifiedBy;
                this.ItemIcon = model.ItemIcon;
                this.IsSelected = model.IsSelected;
                this.Parent = model.Parent;

                foreach (BaseRegMgrModel child in model.Children)
                {
                    BaseRegMgrModel currentChild = BaseRegMgrModel.GetModelById(child.Id, model.Children, child.Parent);
                    if (currentChild != null)
                    {
                        currentChild.Update(child);
                    }
                }
            }
        }
        /// <summary>
        /// Checks the equality.
        /// </summary>
        /// <param name="obj1">The obj1.</param>
        /// <param name="obj2">The obj2.</param>
        /// <returns></returns>
        public static bool CheckEquality(object item1, object item2)
        {
            bool equal = false;
            if ((item1 == null && item2 == null) ||
                (item1 != null && item2 != null && item1.Equals(item2)))
            {
                equal = true;
            }

            return equal;
        }

        /// <summary>
        /// Checks the equality.
        /// </summary>
        /// <param name="str1">The STR1.</param>
        /// <param name="str2">The STR2.</param>
        /// <returns></returns>
        public static bool CheckEquality(string item1, string item2)
        {
            bool equal = false;
            if ((string.IsNullOrEmpty(item1) && string.IsNullOrEmpty(item2)) ||
                (!string.IsNullOrEmpty(item1) && !string.IsNullOrEmpty(item2) && item1.Equals(item2)))
            {
                equal = true;
            }

            return equal;
        }
    }

    /// <summary>
    /// Helper class for comparing 2 WorkflowViewModels.
    /// </summary>
    public class WorkflowModelComparer : IEqualityComparer<WorkflowViewModel>
    {
        #region IEqualityComparer<WorkflowViewModel> Members

        /// <summary>
        /// Determines whether the specified objects are equal.
        /// </summary>
        /// <param name="x">The first object of type <paramref name="T"/> to compare.</param>
        /// <param name="y">The second object of type <paramref name="T"/> to compare.</param>
        /// <returns>
        /// true if the specified objects are equal; otherwise, false.
        /// </returns>
        public bool Equals(WorkflowViewModel x, WorkflowViewModel y)
        {
            return (x.WorkflowName.Equals(y.WorkflowName, StringComparison.OrdinalIgnoreCase));
        }

        /// <summary>
        /// Returns a hash code for the specified object.
        /// </summary>
        /// <param name="obj">The <see cref="T:System.Object"/> for which a hash code is to be returned.</param>
        /// <returns>A hash code for the specified object.</returns>
        /// <exception cref="T:System.ArgumentNullException">
        /// The type of <paramref name="obj"/> is a reference type and <paramref name="obj"/> is null.
        /// </exception>
        public int GetHashCode(WorkflowViewModel obj)
        {
            return obj.WorkflowName.GetHashCode();
        }

        #endregion
    }
}
